package com.nervenets.web.controller.knowledge;

import cn.binarywang.wx.miniapp.api.WxMaService;
import com.nervenets.utils.StringUtils;
import com.nervenets.web.config.wx.WxMAConfiguration;
import com.nervenets.web.controller.BaseController;
import com.nervenets.web.controller.IdParams;
import com.nervenets.web.controller.IdTokenParams;
import com.nervenets.web.entity.KeyValue;
import com.nervenets.web.entity.MessageCode;
import com.nervenets.web.entity.ResponseResult;
import com.nervenets.web.hibernate.dao.KnowledgeDao;
import com.nervenets.web.hibernate.dao.KnowledgeFavDao;
import com.nervenets.web.hibernate.dao.TagsDao;
import com.nervenets.web.hibernate.domain.knowledge.Knowledge;
import com.nervenets.web.hibernate.domain.knowledge.KnowledgeFav;
import com.nervenets.web.hibernate.domain.knowledge.Tags;
import com.nervenets.web.rabbitmq.FlowMessage;
import com.nervenets.web.rabbitmq.FlowType;
import com.nervenets.web.redis.domain.user.UserStored;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import me.chanjar.weixin.common.error.WxErrorException;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.persistence.criteria.Predicate;
import javax.validation.ConstraintViolation;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

@Api(value = "知识库接口v1", description = "知识库相关接口")
@RestController
@RequestMapping("/api/v1/knowledge")
public class KnowledgeController extends BaseController {
    @Resource
    private KnowledgeDao knowledgeDao;
    @Resource
    private TagsDao tagsDao;
    @Resource
    private KnowledgeFavDao knowledgeFavDao;

    @ApiOperation("查看知识库详情")
    @PostMapping("/detail")
    public ResponseResult detail(@RequestBody IdParams params) {
        final Set<ConstraintViolation<IdParams>> errors = validator.validate(params);
        if (!errors.isEmpty()) {
            return errorMessage(errors);
        }
        final Knowledge object = knowledgeDao.findById(params.getTargetId()).orElse(null);
        if (null == object) return errorMessage(MessageCode.code_404, "您查看的知识库不存在");
        UserStored user = globalService.getUser(object.getUserId());

        return successMessage(object, new KeyValue("user", user), new KeyValue("shareContent", StringUtils.clearHtmlTags(object.getContent())));
    }

    @ApiOperation("知识库新建或修改")
    @PostMapping("/edit")
    public ResponseResult edit(@RequestBody KnowledgeEditParams params) throws Exception {
        if (params.tokenIllegal()) return errorMessage(MessageCode.code_777);
        final Set<ConstraintViolation<KnowledgeEditParams>> errors = validator.validate(params);
        if (!errors.isEmpty()) {
            return errorMessage(errors);
        }

        Set<Tags> tags = new HashSet<>();
        for (Long tagsId : params.getTagsIds()) {
            final Tags tag = tagsDao.findById(tagsId).orElse(null);
            if (null == tag) return errorMessage(MessageCode.code_404, String.format("标签%s不存在", tagsId));
            tags.add(tag);
        }

        Knowledge knowledge = new Knowledge();
        if (params.getKnowledgeId() > 0) {
            knowledge = knowledgeDao.findById(params.getKnowledgeId()).orElse(null);
            if (null == knowledge) return errorMessage(MessageCode.code_404, "您修改的知识库不存在");
        }
        knowledge.setManagerId(params.getManagerId());
        knowledge.setUserId(params.getUserId());
        knowledge.getTags().clear();
        knowledge.setTags(tags);
        knowledge.setTitle(params.getTitle());
        knowledge.setContent(params.getContent());
        knowledge.setAttachments(params.getAttachments());
        knowledgeDao.save(knowledge);

        for (Tags tag : tags) {
            messageProducer.flow(new FlowMessage(0, FlowType.tagsCount, 0, tag.getId()));
        }

        if (StringUtils.isEmpty(knowledge.getQrCode())) {
            try {
                final WxMaService wxMaService = WxMAConfiguration.getMaService(0);
                final String qrCode = saveQrCode(wxMaService.getQrcodeService().createQrcodeBytes("pages/index/index?type=knowledge&id=" + knowledge.getId(), 500), knowledge.getId());
                knowledge.setQrCode(qrCode);
                knowledgeDao.save(knowledge);
            } catch (WxErrorException e) {
                e.printStackTrace();
            }
        }

        return successMessage(knowledge);
    }

    @ApiOperation("知识库列表")
    @PostMapping("/list")
    public ResponseResult list(@RequestBody KnowledgePagingParams params) {
        final Set<ConstraintViolation<KnowledgePagingParams>> errors = validator.validate(params);
        if (!errors.isEmpty()) {
            return errorMessage(errors);
        }

        Specification<Knowledge> specification = (Specification<Knowledge>) (root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();
            predicates.add(criteriaBuilder.equal(root.get("removed"), 0));
            if (params.getManagerId() > 0) {
                predicates.add(criteriaBuilder.equal(root.get("managerId"), params.getManagerId()));
            }
            if (params.getUserId() > 0) {
                predicates.add(criteriaBuilder.equal(root.get("userId"), params.getUserId()));
            }
            if (params.getTagsId() > 0) {
                predicates.add(criteriaBuilder.equal(root.join("tags").get("id"), params.getTagsId()));
            }
            if (!StringUtils.isEmpty(params.getKeyword())) {
                final Predicate or = criteriaBuilder.or(
                        criteriaBuilder.like(root.get("title"), "%" + params.getKeyword() + "%"),
                        criteriaBuilder.like(root.get("content"), "%" + params.getKeyword() + "%")
                );
                predicates.add(or);
            }
            return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
        };
        Page<Knowledge> page = knowledgeDao.findAll(specification, PageRequest.of(params.getPage(), params.getLimit(), new Sort(Sort.Direction.DESC, "id")));
        List<KnowledgeDto> dtos = new ArrayList<>();
        page.map(knowledge -> dtos.add(new KnowledgeDto(knowledge, globalService)));
        if (params.getTagsId() > 0) {
            tagsDao.weightAdd(params.getTagsId());
        }
        return successMessage(dtos, new KeyValue("page", params.getPage()), new KeyValue("total", page.getTotalElements()));
    }

    @ApiOperation("知识库删除")
    @PostMapping("/del")
    public ResponseResult del(@RequestBody IdTokenParams params) {
        final Set<ConstraintViolation<IdTokenParams>> errors = validator.validate(params);
        if (!errors.isEmpty()) {
            return errorMessage(errors);
        }
        Knowledge knowledge = knowledgeDao.findById(params.getTargetId()).orElse(null);
        if (null == knowledge) return errorMessage(MessageCode.code_404, "您要删除的知识库不存在");
        //knowledge.setRemoved(JodaUtils.getTimestamp());
        knowledgeDao.delete(knowledge);
        return successMessage();
    }

    @ApiOperation("知识库收藏")
    @PostMapping("/fav")
    public ResponseResult fav(@RequestBody IdTokenParams params) throws Exception {
        if (params.tokenIllegal()) return errorMessage(MessageCode.code_777);
        final Set<ConstraintViolation<IdTokenParams>> errors = validator.validate(params);
        if (!errors.isEmpty()) {
            return errorMessage(errors);
        }
        Knowledge knowledge = knowledgeDao.findById(params.getTargetId()).orElse(null);
        if (null == knowledge) return errorMessage(MessageCode.code_404, "您要收藏的知识库不存在");

        KnowledgeFav fav = knowledgeFavDao.findByUserIdAndKnowledge(params.resolveUserId(), knowledge);
        if (null == fav) fav = new KnowledgeFav(params.resolveUserId(), knowledge);
        knowledgeFavDao.save(fav);

        return successMessage();
    }

    @ApiOperation("知识库取消收藏")
    @PostMapping("/favCancel")
    public ResponseResult favCancel(@RequestBody IdTokenParams params) throws Exception {
        if (params.tokenIllegal()) return errorMessage(MessageCode.code_777);
        final Set<ConstraintViolation<IdTokenParams>> errors = validator.validate(params);
        if (!errors.isEmpty()) {
            return errorMessage(errors);
        }
        Knowledge knowledge = knowledgeDao.findById(params.getTargetId()).orElse(null);
        if (null == knowledge) return errorMessage(MessageCode.code_404, "您要收藏的知识库不存在");

        KnowledgeFav fav = knowledgeFavDao.findByUserIdAndKnowledge(params.resolveUserId(), knowledge);
        if (null != fav) knowledgeFavDao.delete(fav);

        return successMessage();
    }

    @ApiOperation("知识库判断收藏")
    @PostMapping("/checkFav")
    public ResponseResult checkFav(@RequestBody IdTokenParams params) {
        if (params.tokenIllegal()) return errorMessage(MessageCode.code_777);
        final Set<ConstraintViolation<IdTokenParams>> errors = validator.validate(params);
        if (!errors.isEmpty()) {
            return errorMessage(errors);
        }
        Knowledge knowledge = knowledgeDao.findById(params.getTargetId()).orElse(null);
        if (null == knowledge) return errorMessage(MessageCode.code_404, "您要查看的知识库不存在");

        KnowledgeFav fav = knowledgeFavDao.findByUserIdAndKnowledge(params.resolveUserId(), knowledge);

        return successMessage(null != fav);
    }

    @ApiOperation("知识库收藏列表")
    @PostMapping("/favs")
    public ResponseResult favs(@RequestBody FavsPagingParams params) throws Exception {
        if (params.tokenIllegal()) return errorMessage(MessageCode.code_777);
        final Set<ConstraintViolation<FavsPagingParams>> errors = validator.validate(params);
        if (!errors.isEmpty()) {
            return errorMessage(errors);
        }
        Specification<KnowledgeFav> spec = (Specification<KnowledgeFav>) (root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();
            predicates.add(criteriaBuilder.equal(root.get("removed"), 0));
            predicates.add(criteriaBuilder.equal(root.get("userId"), params.resolveUserId()));
            if (!StringUtils.isEmpty(params.getKeyword())) {
                final Predicate or = criteriaBuilder.or(
                        criteriaBuilder.like(root.get("knowledge").get("title"), "%" + params.getKeyword() + "%"),
                        criteriaBuilder.like(root.get("knowledge").get("content"), "%" + params.getKeyword() + "%")
                );
                predicates.add(or);
            }
            return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
        };
        final Page<KnowledgeFav> favs = knowledgeFavDao.findAll(spec, PageRequest.of(params.getPage(), params.getLimit(), new Sort(Sort.Direction.DESC, "id")));
        List<Knowledge> knowledges = new ArrayList<>();
        favs.forEach(knowledgeFav -> {
            knowledges.add(knowledgeFav.getKnowledge());
        });
        return successMessage(knowledges, new KeyValue("page", params.getPage()), new KeyValue("total", favs.getTotalElements()));
    }
}
